home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
101-125
/
103
/
cref
/
cref.orig.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-13
|
20KB
|
1,027 lines
/*
** cref - C cross referencer
** This program reads its standard input or one or more files
** and prints the file plus an alphabetic list of word references
** by line number.
**
** When run using the `-b' option the program keeps the word
** list in memory. Otherwise the program uses a temporary
** word list file which is run through `sort'. That way it
** can cross reference extremely large source files.
** Unfortunately it makes the program run slower.
**
** To run:
** cref [-b] [-q] [-lnnn] [-wnnn] [-hheading] [file ...]
**
** Options:
** b - use sort file rather then memory (for large files)
** q - don't print normal input file listing
** lnnn - set page length to n instead of the default 66.
** wnnn - set page width to n instead of the default 132.
** hccc - set page heading to 'ccc' rather than file names
**
** Mike Edmonds - 5/81
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAXWORD 15 /* maximum chars in word */
#define MAXPAGLINES 9999 /* maximum posible lines in page */
#define MAXLINWIDTH 132 /* maximum posible chars in line */
#define igncase(c) (isupper(c)? tolower(c) : (c))
#define FALSE 0
#define TRUE 1
#ifdef DEBUG
#define debug(a,b) fprintf(stderr,(a),(b))
#else
#define debug(a,b)
#endif
/*
* global structures
*/
#define LINLIST struct _linlist
#define WRDLIST struct _wrdlist
struct _linlist { /* line number list node */
long ln_no ; /* line number */
LINLIST *ln_next ; /* next element pointer (or NULL) */
} ;
struct _wrdlist { /* word list node */
char *wd_wd ; /* pointer to word */
char *wd_lwd ; /* pointer to word (lower case) */
LINLIST wd_ln ; /* first element of line list */
WRDLIST *wd_low ; /* lower child */
WRDLIST *wd_hi ; /* higher child */
} ;
/*
* options
*/
char *Progname ;
int Bigcref = FALSE ; /* use sort file rather than memory? (-b) */
int Quiet = FALSE ; /* don't print input file listing? (-q) */
int Maxpaglines = 66 ; /* maximum lines in page (-l) */
int Maxlinwidth = 132 ; /* maximum chars in print line (-w) */
/*
* global variables
*/
char Crefhdr[MAXLINWIDTH+1] ;/* report header */
char *Filename ; /* name of current input file */
char Date[30] ; /* current or last file modify date */
long Hiline = 1L ; /* current (and max.) input file line number */
char *Wordfile ; /* temp. word file name */
FILE *Wdfile ; /* temp. word file ptr */
WRDLIST *Wdtree = NULL ; /* ptr to root node of binary word list */
/*
* C language reserved keywords (in pseudo random order)
*/
char *Ckeywords[] = {
"char",
"static",
"break",
"#define",
"#if",
"default",
"#ifdef",
"#ifndef",
"register",
"void",
"if",
"while",
"#line",
"union",
"switch",
"#else",
"asm",
"do",
"#include",
"#undef",
"#endif",
"long",
"continue",
"float",
"short",
"typedef",
"for",
"struct",
"case",
"else",
"unsigned",
"int",
"extern",
"auto",
"goto",
"entry",
"return",
"double",
"sizeof",
0
} ;
onintr(signo) /* handle interrupts */
{
signal(signo, SIG_IGN) ;
unlink(Wordfile) ;
exit(EOF) ;
}
/*
* main - Store C keywords.
* Get program options and format heading lines.
* Get words from input file (or files) and store in temp file or tree.
* Retrieve and print in word sequence.
*/
main(argc, argv)
int argc ;
char *argv[] ;
{
char *mktemp(), wordfilebuf[BUFSIZ] ;
register FILE *filep ;
char *getword(), *word ;
struct stat stbuf ;
long time() ;
register cnt ;
int files=0 ;
Progname = *argv ; /* get options */
getcmd(argc, argv) ;
/* make unique word file name */
Wordfile = mktemp("/tmp/crefXXXXXX") ;
/* catch interrupts */
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
signal(SIGHUP, onintr) ;
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, onintr) ;
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, onintr) ;
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
signal(SIGTERM, onintr) ;
/* open word file */
if ((Wdfile = fopen(Wordfile, "w")) == NULL)
fatal("can't open temp file `%s'", Wordfile) ;
setbuf(Wdfile, wordfilebuf) ;
/* store C keywords */
for (cnt=0 ; Ckeywords[cnt] ; cnt++)
storword(Ckeywords[cnt], 0L) ;
/* read and store files */
for (cnt=1 ; cnt < argc ; cnt++)
if (*argv[cnt] != '-')
{ files++ ;
Filename = argv[cnt] ;
if ((filep = fopen(Filename, "r")) == NULL)
fatal("can't open %s", Filename) ;
fstat(fileno(filep), &stbuf) ;
mkdate((long)stbuf.st_mtime) ;
while (word = getword(filep))
storword(word, Hiline);
fclose(filep) ;
}
if (!files) /* no files - read stdin */
{ if (*Crefhdr)
Filename = Crefhdr ;
else
Filename = "stdin" ;
mkdate(time(0)) ;
while (word = getword(stdin))
storword(word, Hiline) ;
}
fclose(Wdfile) ; /* print cross reference report */
if (Bigcref)
bigcref() ;
else
cref(Wdtree) ;
unlink(Wordfile) ;
exit(0) ;
}
/*
* getcmd - get arguments from command line & build page headings
*/
getcmd(argc, argv)
register argc ;
register char *argv[] ;
{
register cnt ;
debug("GETCMD(%d", argc) ;
debug(", %s)\n", argv[0]) ;
*Crefhdr = '\0' ;
/* get command options */
for (cnt=1; cnt < argc; cnt++)
{ if (*argv[cnt] == '-')
{ switch(argv[cnt][1])
{ case 'b':
Bigcref = TRUE ;
break ;
case 'q':
Quiet = TRUE ;
break ;
case 'l':
Maxpaglines = atoi(&argv[cnt][2]) ;
if (Maxpaglines < 4
|| Maxpaglines > MAXPAGLINES)
fatal("size error: %s", argv[cnt]) ;
break ;
case 'w':
Maxlinwidth = atoi(&argv[cnt][2]) ;
if (Maxlinwidth < MAXWORD+12
|| Maxlinwidth > MAXLINWIDTH)
fatal("size error: %s", argv[cnt]) ;
break ;
case 'h':
strncpy(Crefhdr, &argv[cnt][2], MAXLINWIDTH) ;
Crefhdr[MAXLINWIDTH] = '\0' ;
break ;
default:
fatal("invalid option: %s", argv[cnt]) ;
}
}
}
/* insert file names in hdr */
if (!*Crefhdr)
for (cnt=1; cnt < argc; cnt++)
if (*argv[cnt] != '-')
strjoin(Crefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
}
/*
* getword - read, print and return next word from file
*/
char *
getword(filep)
FILE *filep ;
{
static char wordbuf[MAXWORD+1] ;
register char *wp = wordbuf ;
register maxw = sizeof(wordbuf) ;
register chr ;
int inword=0, lastchr=0 ;
long slineno ;
#define _listchr(chr) if (!Quiet) listchr(chr)
#define _rtrnwrd(wp) \
{ ungetc(chr, filep) ; \
*(wp) = '\0' ; \
return wordbuf ; \
}
while ((chr = getc(filep)) != EOF)
{ switch (chr)
{ /* normal char - add to current word */
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
case '_':
if (maxw-- <= 1)
_rtrnwrd(wp) ;
*wp++ = chr ;
inword++ ;
_listchr(chr) ;
break ;
/* digit - can't be 1st char in word */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (inword)
{ if (maxw-- <= 1)
_rtrnwrd(wp) ;
*wp++ = chr ;
}
_listchr(chr) ;
break ;
/* '#' - must be 1st char in word */
case '#':
if (inword)
_rtrnwrd(wp) ;
*wp++ = chr ;
inword++ ;
_listchr(chr) ;
break ;
/* newline - end current word */
case '\n':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
Hiline++ ;
break ;
/* comments - print & bypass */
case '/':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
slineno = Hiline ;
if ((chr = getc(filep)) == '*')
{ _listchr(chr) ;
while (chr != EOF)
{ chr = getc(filep) ;
_listchr(chr) ;
if (chr == '\n')
Hiline++ ;
else if (chr == '*')
{ chr = getc(filep) ;
_listchr(chr) ;
if (chr == '\n')
Hiline++ ;
else if (chr == '/')
break ; ;
}
}
if (chr == EOF)
fatal("unterminated comment at %ld in %s", slineno, Filename) ;
}
else
ungetc(chr, filep) ;
break ;
/* words in quotes - print & bypass */
case '"':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
slineno = Hiline ;
if (lastchr != '\\')
{ do
{ if (chr == '\\' && lastchr == '\\')
lastchr = '\0' ;
else
lastchr = chr ;
if ((chr = getc(filep)) == EOF)
fatal("unterminated quote at %ld in %s", slineno, Filename) ;
_listchr(chr) ;
if (chr == '\n')
Hiline++ ;
} while (chr != '"' || lastchr == '\\') ;
}
break ;
/* letters in quotes - print & bypass */
case '\'':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
if (isprint(chr = getc(filep)))
{ _listchr(chr) ;
if (chr == '\\')
{ if (!isprint(chr = getc(filep)))
goto toofar ;
_listchr(chr) ;
}
if ((chr = getc(filep)) != '\'')
goto toofar ;
_listchr(chr) ;
}
else
toofar:
ungetc(chr, filep) ;
break ;
default:
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
break ;
}
lastchr = chr ;
}
if (inword)
_rtrnwrd(wp) ;
_listchr(EOF) ;
return NULL ;
}
/*
* listchr - list the input files one character at a time
*/
static Listpage = 0 ;
static Listpline = MAXPAGLINES ;
listchr(chr)
register chr ;
{
static char linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
static lastchr=0, linecnt=0 ;
if (chr == EOF) /* EOF - print final line */
{ *lineptr = '\0' ;
listline(linebuf) ;
Listpage = 0 ;
Listpline = MAXPAGLINES ;
lineptr = linebuf ;
linecnt = 0 ;
return ;
}
if (lineptr == linebuf) /* new line - format line number */
{ ltoc(linebuf, Hiline, 6) ;
lineptr = linebuf+6 ;
*lineptr++ = '\t' ;
linecnt = 8 ;
}
#define _lineoflo(ctr, newctr) \
if ((ctr) >= Maxlinwidth) \
{ *lineptr = '\0' ; \
listline(linebuf) ; \
lineptr = linebuf ; \
*lineptr++ = '\t' ; \
linecnt = (newctr) ; \
}
switch (chr)
{ /* newline - print last line */
case '\n':
if (lastchr != '\f')
{ *lineptr = '\0' ;
listline(linebuf) ;
}
lineptr = linebuf ;
linecnt = 0 ;
break ;
/* formfeed - print line and end page */
case '\f':
if (linecnt != 8)
{ *lineptr = '\0' ;
listline(linebuf) ;
}
Listpline = MAXPAGLINES ;
lineptr = linebuf ;
linecnt = 0 ;
break ;
/* tab - skip to next tab stop */
case '\t':
linecnt += 8 ;
linecnt &= ~07 ;
_lineoflo(linecnt, 16) ;
*lineptr++ = chr ;
break ;
/* backspace - print, but don't count */
case '\b':
*lineptr++ = chr ;
break ;
/* ctl-char - print as "^x" */
case 001: case 002: case 003:
case 004: case 005: case 006: case 007:
case 013:
case 015: case 016: case 017:
case 020: case 021: case 022: case 023:
case 024: case 025: case 026: case 027:
case 030: case 031: case 032: case 033:
case 034: case 035: case 036: case 037:
_lineoflo(linecnt+=2, 10) ;
*lineptr++ = '^' ;
*lineptr++ = ('A'-1) + chr ;
break ;
/* printable chars */
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case ' ':
case '!': case '"': case '#': case '$': case '%':
case '&': case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/': case ':':
case ';': case '<': case '=': case '>': case '?':
case '@': case '[': case ']': case '^': case '_':
case '`': case '{': case '|': case '}': case '~':
case '\'': case '\\':
_lineoflo(++linecnt, 9) ;
*lineptr++ = chr ;
break ;
default:
if (isprint(chr))
{ _lineoflo(++linecnt, 9) ;
*lineptr++ = chr ;
}
else /* non-ascii chars - print as "\nnn" */
{ _lineoflo(linecnt+=4, 12) ;
*lineptr++ = '\\' ;
*lineptr++ = '0' + ((chr & 0300) >> 6) ;
*lineptr++ = '0' + ((chr & 070) >> 3) ;
*lineptr++ = '0' + (chr & 07) ;
}
break ;
}
lastchr = chr ;
}
/* print a completed line from the input file */
listline(line)
register char *line ;
{
if (*line)
{ if (++Listpline >= (Maxpaglines-8))
{ putchar('\f') ;
printf("\n%s %s Page %d\n\n",
Date, Filename, ++Listpage) ;
Listpline = 0 ;
}
puts(line) ;
}
}
/*
* storword - store word and line # in binary word tree or word file
*/
#define _writeword(word, lword, lineno) \
fprintf(Wdfile, "%s\t%s\t%06ld\n", (lword), (word), (lineno))
storword(word, lineno)
register char *word ;
long lineno ;
{
char lword[MAXWORD+1] ;
register char *cp1, *cp2 ;
WRDLIST *addword() ;
/* convert word to lower case */
for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
;
/* store words and lineno */
if (Bigcref)
_writeword(word, lword, lineno) ;
else
Wdtree = addword(Wdtree, word, lword, lineno) ;
}
/*
* addword - add word and line# to in-core word list
*/
WRDLIST *
addword(wdp, word, lword, lineno)
register WRDLIST *wdp ;
char *word, *lword ;
long lineno ;
{
char *malloc() ;
int comp ;
/* insert new word into list */
if (wdp == NULL)
{ register wordlen = strlen(word) + 1 ;
wdp = (WRDLIST *)malloc((wordlen * 2) + sizeof(WRDLIST)) ;
if (wdp == NULL)
goto nomemory ;
wdp->wd_wd = (char *)wdp + sizeof(WRDLIST) ;
wdp->wd_lwd = wdp->wd_wd + wordlen ;
strcpy(wdp->wd_wd, word) ;
strcpy(wdp->wd_lwd, lword) ;
wdp->wd_hi = wdp->wd_low = NULL ;
wdp->wd_ln.ln_no = lineno ;
wdp->wd_ln.ln_next = NULL ;
}
/* word matched in list? */
else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
&& ((comp = strcmp(word, wdp->wd_wd)) == 0))
{ register LINLIST *lnp, **lnpp ;
if (wdp->wd_ln.ln_no)
{ /* add line# to linked list */
lnp = &wdp->wd_ln ;
do
{ if (lineno == lnp->ln_no)
return wdp ;
lnpp = &lnp->ln_next ;
} while ((lnp = *lnpp) != NULL) ;
*lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
if ((lnp = *lnpp) == NULL)
goto nomemory ;
lnp->ln_no = lineno ;
lnp->ln_next = NULL ;
}
}
else if (comp < 0) /* search for word in children */
wdp->wd_low = addword(wdp->wd_low, word, lword, lineno) ;
else
wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
return wdp ;
/* not enough memory - convert to -b */
nomemory:
error("not enough memory for in-core word list - using -b option") ;
_writeword(word, lword, lineno) ; /* write current word in file */
dumptree(Wdtree) ; /* dump tree into file */
Bigcref = TRUE ;
return wdp ;
}
/*
* dumptree - ran out of memory for in-core word list - dump tree into file
*/
dumptree(wdp)
register WRDLIST *wdp ;
{
register LINLIST *lnp ;
if (wdp != NULL)
{ dumptree(wdp->wd_low) ; /* dump children */
dumptree(wdp->wd_hi) ;
/* dump parent */
_writeword(wdp->wd_wd, wdp->wd_lwd, wdp->wd_ln.ln_no) ;
for (lnp=wdp->wd_ln.ln_next ; lnp != NULL ; lnp=lnp->ln_next)
{ _writeword(wdp->wd_wd, wdp->wd_lwd, lnp->ln_no) ;
free((char *)lnp) ;
}
free((char *)wdp) ;
}
}
/*
* cref - print cross reference report from internal word list
*/
#define MAXLNOS 2000 /* maximum line nos. for a word */
long Linenos[MAXLNOS] ; /* list of line numbers for a word */
cref(wdtree)
register WRDLIST *wdtree ;
{
creftree(wdtree) ;
putchar('\f') ;
}
creftree(wdp) /* recursively print word tree nodes */
register WRDLIST *wdp ;
{
register LINLIST *lnp ;
register nos ;
if (wdp != NULL)
{ creftree(wdp->wd_low) ; /* print lower children */
nos = 0 ;
if (Linenos[0] = wdp->wd_ln.ln_no)
{ lnp = &wdp->wd_ln ;
while ((lnp = lnp->ln_next) != NULL)
if (nos < (MAXLNOS-2))
Linenos[++nos] = lnp->ln_no ;
printword(wdp->wd_wd, nos) ;
}
creftree(wdp->wd_hi) ; /* print higher children */
}
}
/*
* bigcref - print cross reference report from word file
*/
bigcref()
{
char oldword[MAXWORD+1], word[MAXWORD+1], lword[MAXWORD+1] ;
long lineno ;
register args, nos ;
int pid, child, status ;
/* sort word file */
if ((child = fork()) == 0)
{ execl("/usr/bin/sort", "sort", "-o", Wordfile, Wordfile, 0);
fatal("can't execute /bin/sort") ;
}
while (((pid = wait(&status)) != child) && (pid >= 0))
;
if ((pid < 0) || status)
fatal("can't sort temp file `%s'", Wordfile) ;
/* re-open word file */
if ((Wdfile = fopen(Wordfile, "r")) == NULL)
fatal("can't open temp file `%s'", Wordfile) ;
#define _readword() fscanf(Wdfile, "%s %s %ld", lword, word, &lineno)
args = _readword() ;
while (args == 3)
{ strcpy(oldword, word) ;
if (Linenos[0] = lineno)
{ nos = 0 ;
while ((args = _readword()) == 3)
{ if (strcmp(word, oldword))
break ;
if ((Linenos[nos] != lineno)
&& (nos < (MAXLNOS-2)))
Linenos[++nos] = lineno ;
}
printword(oldword, nos) ;
}
else
while ((args = _readword()) == 3)
if (strcmp(word, oldword))
break ;
}
putchar('\f') ;
fclose(Wdfile) ;
}
/*
* printword - print a word and all its line number references
*/
printword(word, nos)
char *word ;
register nos ;
{
static firstime=TRUE, linecnt, maxlnos, lnosize ;
register cnt ;
if (firstime)
{ firstime = FALSE ;
linecnt = Maxpaglines ;
for (lnosize=1 ; Hiline ; lnosize++)
Hiline /= 10L ;
maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
}
if (linecnt >= (Maxpaglines - 8))
{ printheads() ;
linecnt = 5 ;
}
printf("%-15s%5d ", word, ++nos) ;
Linenos[nos] = 0 ;
for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
{ if (++cnt > maxlnos)
{ cnt = 1 ;
if (linecnt++ >= (Maxpaglines - 2))
{ printheads() ;
linecnt = 5 ;
printf("%-15s(cont) ", word);
}
else
printf("\n%22s", " ") ;
}
printf("%*ld", lnosize, Linenos[nos]) ;
}
putchar('\n') ;
linecnt++ ;
}
/*
* printheads - print page headings
*/
printheads()
{
static page=0 ;
long time() ;
if (!page)
mkdate(time(0)) ;
putchar('\f') ;
printf("\nCREF %s %.*s Page %d\n\n",
Date, (Maxlinwidth-36), Crefhdr, ++page) ;
printf("word refs line numbers\n\n") ;
}
/*
* ltoc - store ASCII equivalent of long value in given field
*/
ltoc(fld, lval, len)
register char *fld ;
register long lval ;
register len ;
{
fld += len ;
while (len-->0)
if (lval)
{ *--fld = '0' + (lval%10L) ;
lval /= 10L ;
}
else
*--fld = ' ' ;
}
/*
* mkdate - build time/date for use in heading lines
*/
mkdate(atime)
long atime ;
{
long mtime ;
char *cp, *ctime() ;
debug("MKDATE(%ld)\n", atime) ;
mtime = atime ;
cp = ctime(&mtime) ;
*(cp+24) = ' ' ; /* clear newline */
strcpy(cp+16, cp+19) ; /* shift over seconds */
strcpy(Date, cp+4) ;
}
/*
* strjoin - join "str1" to "str2" (separated by "sep")
* Truncate if necessary to "max" chars.
*/
strjoin(str1, sep, str2, max)
register char *str1, *str2;
char sep ;
register max ;
{
if (*str2)
{ if (*str1)
{ while (*str1++)
if (--max <= 0)
goto oflo ;
max--, str1-- ;
*str1++ = sep ;
}
while (*str1++ = *str2++)
if (--max <= 0)
goto oflo ;
}
return ;
oflo:
*--str1 = '\0' ;
return ;
}
/*
* error - print standard error msg
*/
error(ptrn, data1, data2)
register char *ptrn, *data1, *data2 ;
{
fprintf(stderr, "%s: ", Progname) ;
fprintf(stderr, ptrn, data1, data2) ;
putc('\n', stderr) ;
}
/*
* fatal - print standard error msg and halt process
*/
fatal(ptrn, data1, data2)
register char *ptrn, *data1, *data2 ;
{
error(ptrn, data1, data2) ;
kill(getpid(), SIGTERM) ;
}